#include "N2BitmapRep.h"

N2BitmapRep::N2BitmapRep(uint16 bitsPerPixel, uint32 width, uint32 height) : m_size(width, height)
{
    switch(bitsPerPixel)
    {
        case 1:
        case 4:
        case 8:
        case 16:
        case 24:
        case 32:
            break;
        default:
            N1ThrowException1("Can't create N2BitmapRep with %u bits per pixel.", bitsPerPixel);
    }

    m_nByteInRow = ( width * bitsPerPixel + 31) / 32 * 4;
    m_nSize = m_nByteInRow * height;
    m_pData = NULL;
    m_pData = (char*)N1Malloc( m_nSize );
    memset(m_pData, 0xFF, m_nSize);
    m_nBPP = bitsPerPixel;
}

N2BitmapRep::~N2BitmapRep()
{
    N1Free(m_pData);
}

uint32 N2BitmapRep::getPixel(uint32 x, uint32 y) const 
{
    uint32 ret = 0;

    if(!m_size.inRectFromSize(x, y)) return 0;

    BYTE *pRow = (BYTE*)m_pData + m_nByteInRow * y;

    switch(m_nBPP) 
    {
        case 1:
            ret = (*(pRow + x/8) >> x%8) & 1;
            if(ret) ret = RGB(255,255,255);
            break;
        case 4:
            if(x&1)
                ret = (*(pRow + x/2) & 0xF);
            else
                ret = (*(pRow + x/2) >> 4);
            break;
        case 8:
            ret = *(pRow + x);
            break;
        case 16:
            ret = *((uint16*)pRow + x);
            break;
        case 24:
            pRow += x*3;
            ret = (*pRow++) | (*pRow++)<<8  | (*pRow)<<16;
            break;
        case 32:
            ret = *((uint32*)pRow + x);
            break;
    }
    return ret;
}

void N2BitmapRep::setPixel(uint32 x, uint32 y, uint32 color)
{
    if(!m_size.inRectFromSize(x, y)) return;

    uint8 *pRow = (uint8*)m_pData + m_nByteInRow * y;

    switch(m_nBPP)
    {
        case 1:
            if(color) 
                *(pRow + x/8) |= (1<<x%8);
            else 
                *(pRow + x/8) &= ~(1<<x%8);
            break;
        case 4:
            *(pRow + x/2) &= ((0xF) << (4*(x&1)));
            if(x&1)
                *(pRow + x/2) |= ((uint8)color);
            else
                *(pRow + x/2) |= ((uint8)color << 4);
            break;
        case 8:
            *(pRow + x) = (uint8)color;
            break;
        case 16:
            *((uint16*)pRow + x) = (uint16)color;
            break;
        case 24:
            pRow += x*3;
            *pRow++ = GetRValue(color);
            *pRow++ = GetGValue(color);
            *pRow   = GetBValue(color);
            break;
        case 32:
            *((uint32*)pRow + x) = color;
            break;
    }
}

void N2BitmapRep::drawHorzLine(uint32 x1, uint32 x2, uint32 y, uint32 color)
{
    uint32 cx;

    N1SortValues(x1, x2);

    for(cx = x1; cx<=x2; cx++)
    {
        setPixel(cx, y, color);
    }
/*
    switch(m_nBPP)
    {
        case 1:
            {
                uint8 *pRow = (uint8*)m_pData + m_nByteInRow * y;

                uint32 ofs1 = (x1 + 7) / 8; //first byte
                uint32 ofs2 = x2 / 8;       //last byte

                memset(pRow + ofs1, 0, ofs2 - ofs1);

                const uint8 bits[7] =  { 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80 };

                uint8 bitNumber = x1 % 8;
                uint32 byteNumber = x1 / 8;
            }
            break;
    }*/
}

void N2BitmapRep::drawVertLine(uint32 x, uint32 y1, uint32 y2, uint32 color)
{
    uint32 cy;

    N1SortValues(y1, y2);

    for(cy = y1; cy<=y2; cy++)
    {
        setPixel(x, cy, color);
    }
}

bool N2BitmapRep::copyRect(const N2BitmapRep& from, const N2Rect &dest, 
                           uint32 xSrc, uint32 ySrc, N2BitOperation op)
{
    uint32 cx, cy;
    uint32 xLast, yLast;

    if(dest.isEmpty()) return false;

    xLast = dest.right;
    yLast = dest.bottom;

    for(cy = dest.top; cy<yLast; cy++)
    {
        for(cx = dest.left; cx<xLast; cx++)
        {
            uint32 color = from.getPixel(cx, cy);
            setPixel(cx, cy, color);
        }
    }
    return true;
}

bool   N2BitmapRep::stretchRect(const N2BitmapRep& from, const N2Rect &dest, 
                                const N2Rect &src, N2BitOperation op)
{
    uint32 cx, cy;
    uint32 xLast, yLast;
    float dx, dy;
    float cxSrc, cySrc;

    if(dest.isEmpty()) return false;
    if(src.isEmpty()) return false;

    xLast = dest.right;
    yLast = dest.bottom;

    dx = (double)dest.width() / (double)src.width();
    dy = (double)dest.height() / (double)src.height();

    for(cy = dest.top, cySrc = src.left; cy<yLast; cy++, cySrc+= dy)
    {
        for(cx = dest.left, cxSrc = src.left; cx<xLast; cx++, cxSrc += dx)
        {
            uint32 color = from.getPixel(static_cast<uint32>(cxSrc), static_cast<uint32>(cySrc));
            setPixel(cx, cy, color);
        }
    }

    return true;
}
